<template>
  <view ref="tm-dragList" class="tm-dragList flex flex-col flex-col-center-center">
    <view
      :style="{ height: h * list.length + 'px', width: w + 'px' }"
      class="relative flex flex-col"
      :class="[disabled ? 'opacity-4' : '']"
    >
      <view
        class="overflow flex flex-col"
        :class="['absolute', 'tm-dragList-item', 'flex-between']"
        v-for="(item, index) in listData"
        :key="index"
        :style="[
          {
            top: `${item.top}px`,
            height: h + 'px',
            width: w + 'px',
            zIndex: nowMove_index == index ? 5 : 0,
          },
          isNvue
            ? { 'transition-delay': '0.1s' }
            : {
                'transition-duration':
                  nowMove_index == index || endDrage ? '0s' : '0.25s',
              },
        ]"
      >
        <tm-sheet
          hover-class="opacity-6"
          :border="1"
          border-direction="bottom"
          :color="nowMove_index == index ? 'grey-3' : 'white'"
          _class="flex-1 flex flex-row flex-between"
          class="flex-1"
          :margin="[0, 0]"
          :padding="[0, 0]"
        >
          <view
            class="flex flex-row flex-row-center-start pl-12"
            :style="{ height: h - 1 + 'px' }"
          >
            <view v-if="item['icon']" class="flex-shrink fulled-height flex-center">
              <tm-icon
                :color="item['color']"
                :name="item['icon']"
                :fontSize="40"
              ></tm-icon>
            </view>
            <tm-text _class=" pl-24" :font-size="30" :label="item.text"></tm-text>
          </view>
          <view
            :style="{ height: h - 1 + 'px', width: '100rpx' }"
            @touchstart.stop.prevent="m_start($event, index)"
            @longpress="m_start_longpress(index)"
            @mousedown="m_start($event, index)"
            @touchmove.stop.prevent="m_move($event, index)"
            @mousemove.stop.prevent="m_move($event, index)"
            @touchend="m_end($event, index)"
            @mouseup="m_end($event, index)"
            class="flex-shrink flex flex-row flex-row-center-center opacity-3"
          >
            <tm-icon :userInteractionEnabled="false" name="tmicon-menu"></tm-icon>
          </view>
        </tm-sheet>
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
/**
 * 拖放排序列表
 * @description 在h5和pc端，点击右边区域即可触发拖动。在MP和APP端需要长按右边区域触发拖动排序。
 * @description 已知hack:在nvue端，因zIndex不起作用，导致前端组件移动时，可能会被后面渲染的列表覆盖，但不影响使用，只影响些许美观。
 */
import { Ref, ref, nextTick, toRaw, onMounted, getCurrentInstance, PropType } from "vue";
import tmIcon from "../tm-icon/tm-icon.vue";
import tmSheet from "../tm-sheet/tm-sheet.vue";
import tmText from "../tm-text/tm-text.vue";
import { itemList } from "./interface";
const props = defineProps({
  disabled: {
    type: [String, Boolean],
    default: false,
  },
  width: {
    type: Number,
    default: 700,
  },
  height: {
    type: Number,
    default: 90,
  },
  list: {
    type: Array as PropType<Array<itemList>>,
    default: () => {
      return [];
    },
  },
  rangKey: {
    type: String,
    default: "text",
  },
  rightIcon: {
    type: String,
    default: "icon-menu",
  },
  bgColor: {
    type: String,
    default: "white",
  },
});
const emits = defineEmits(["change"]);
const w = ref(0);
const h = ref(0);
const totalH = ref(0);
let y = 0;
const new_index: Ref<number> = ref(NaN); //即将被替换的索引（实质性被替换）
const nowMove_index: Ref<number> = ref(NaN); //现在正在移动的索引
const listData = ref([]);
let new_item = []; //虚拟列表，内部排列好，但未在页面中渲染。
const endDrage = ref(false);
const isNvue = ref(false);
// #ifdef APP-NVUE
isNvue.value = true;
// #endif
// tm-dragList
onMounted(() => jishunTopData());

function jishunTopData() {
  nextTick(function () {
    listData.value = [];
    w.value = uni.upx2px(props.width) || 700;
    h.value = uni.upx2px(props.height) || 120;
    totalH.value = h.value * props.list.length;
    let list = [];
    for (let i = 0; i < props.list.length; i++) {
      let p: itemList = props.list[i];
      p["top"] = i * h.value;
      p["i"] = i;
      p["__id"] = uni.$tm.u.getUid();
      listData.value.push(p);
    }
    new_item = [...listData.value];
  });
}
function m_start_longpress(index: number) {
  endDrage.value = false;
  nowMove_index.value = index;
  // #ifdef APP-NVUE
  uni.vibrateShort({
    success: function () {},
  });
  // #endif
}

function m_start(event: Event, index: number) {
  event.preventDefault();
  event.stopPropagation();
  if (props.disabled) return;
  // #ifndef APP-NVUE
  endDrage.value = false;
  nowMove_index.value = index;
  // #endif

  new_item = [...listData.value];
  if (event.type.indexOf("mouse") == -1 && event.changedTouches.length == 1) {
    var touch = event.changedTouches[0];
    y = touch.pageY - event.currentTarget.offsetTop - listData.value[index].top;
  } else {
    y = event.pageY - event.currentTarget.offsetTop - listData.value[index].top;
  }

  // #ifdef APP-NVUE || MP
  // uni.vibrateShort()
  // #endif
}
function m_move(event: Event, index: number) {
  if (props.disabled) return;
  event.preventDefault();
  event.stopPropagation();

  if (isNaN(nowMove_index.value)) return;
  //当前元素的top位置。
  let ch = 0;
  if (event.type.indexOf("mouse") == -1 && event.changedTouches.length == 1) {
    var touch = event.changedTouches[0];
    ch = touch.pageY - y;
  } else {
    ch = event.pageY - y;
  }

  listData.value.splice(index, 1, {
    ...listData.value[index],
    top: ch,
  });
  const currenit_index = index;
  const currentSort = listData.value[currenit_index].i;
  const currenit_id = listData.value[currenit_index].__id;

  // 计算当前移动的index.
  let moveIndex = Math.round(ch / h.value);

  moveIndex = moveIndex < 0 ? 0 : moveIndex;
  moveIndex =
    moveIndex > listData.value.length - 1 ? listData.value.length - 1 : moveIndex;

  moveIndex = Math.abs(moveIndex);

  index = moveIndex;
  let elList = [...listData.value];
  for (let i = 0; i < elList.length; i++) {
    if (currentSort < moveIndex) {
      if (elList[i].i > currentSort && elList[i].i <= moveIndex) {
        elList[i].i -= 1;
      }
    } else if (currentSort > moveIndex) {
      if (elList[i].i < currentSort && elList[i].i >= moveIndex) {
        elList[i].i += 1;
      }
    }
  }
  elList[currenit_index].i = moveIndex;
  elList = elList.map((im) => {
    if (im.__id != currenit_id) {
      im.top = im.i * h.value;
    }

    return im;
  });
  listData.value = elList;
  new_index.value = moveIndex;
}
function m_end(event: Event, index: number) {
  if (props.disabled) return;
  event.preventDefault();
  event.stopPropagation();
  nowMove_index.value = NaN;
  endDrage.value = true;
  if (isNaN(new_index.value)) return;
  let elList = [...listData.value];
  elList = elList.map((im) => {
    im.top = im.i * h.value;
    return im;
  });
  elList.sort((a, b) => a.i - b.i);
  listData.value = [...elList];
  moveChange();
}

function moveChange() {
  if (props.disabled) return;
  //change后修改的数据 。
  emits("change", toRaw(listData.value));
}
</script>

<style scoped>
.tm-dragList-item {
  transition-delay: 0s;
  transition-property: top, left, transform;
  transition-timing-function: ease;
  transition-duration: 0.15s;
}
</style>
